package com.xy.auth;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.Jwts;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

import java.nio.charset.StandardCharsets;

@SpringBootApplication
@EnableDiscoveryClient

/**
 * spring security 整合oauth2 流程
 *
 * 1，引入pom：
 * <dependency>
 *             <groupId>org.springframework.cloud</groupId>
 *             <artifactId>spring-cloud-starter-oauth2</artifactId>
 * </dependency>
 *
 * 2,如果不用JWT
 * 参考本项目：AuthServerUserInMemoryConfig
 *
 * 3.如果使用公钥私钥 参考本项目：AuthServerUserJwtPrivatePublicKeyConfig
 *
 * 4，然后还需要配置资源服务器和spring secrity服务器 参考 ResourceServiceConfig 和 WebSecurityConfig
 *
 *
 */

/**
 *授权码模式
 * 请求code:第一步 需要请求下面路径获取code 只需要clientid 和 类型 拿code 并让用户授权
 *http://localhost:8900/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://www.baidu.com&scope=all 或者
 *http://localhost:8900/oauth/authorize?response_type=code&client_id=client
 * 然后使用 localhost:8900/oauth/token post请求 body 体是 code=上一步请求的 和 grant_type=authorization_code
 * 并带上请求头：key 为 Authorization  值 为 (clientid ,client_secret  ==> clientid:client_secret  并对这个字符串进行base64编码 然后在 编码的前面加上"Basic ")
 *      如果是http头 可以使用HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); headers.setBasicAuth(CLIENT_ID,CLIENT_SECRET);
 * 并发到地址：localhost:8900/oauth/token 去获取token
 *
 * 最后拿着得到的token去请求资源路径：localhost:8900/auth/test 同时带上头：key 为Authorization 值为 “bearer +上一步获取的token”
 *
 *
 * implicit: 简化模式 不用用户输入用户名密码 直接拿code
 *http://localhost:8900/oauth/authorize?client_id=client&response_type=token&scope=all&redirect_uri=http://www.baidu.com
 *
 * password模式 直接通过 用户名密码 clientid client secret获取token 不用拿code（授权）
 *  http://localhost:8900/oauth/token?username=fox&password=123456&grant_type=password&client_id=client&client_secret=123123&scope=all
 *
 *  客户端模式   不需要拿code  直接拿着clientid 和clientsecret 获取token 不用拿code（授权）
 *  http://localhost:8900/oauth/token?grant_type=client_credentials&scope=all&client_id=client&client_secret=123123123
 *
 *  刷新令牌
 *  http://localhost:8900/oauth/token?grant_type=refresh_token&client_id=client&client_secret=123123&refresh_token=[refresh_token值]
 */
//如果是 非对称加密 使用证书的形式：需要用这个链接获取公钥：localhost:8900/oauth/token_key  并带上请求头：key 为 Authorization  值 为 (clientid ,client_secret  ==> clientid:client_secret  并对这个字符串进行base64编码 然后在 编码的前面加上"Basic ")
//然后就能判断此token 是不是合法的 通过这个接口拿的有换行符（/n）需要把所有的/n删除

//还有一个接口直接可以检测token是否可用:localhost:8900/oauth/check_token?token=之前获取的token合法性，并返回具体的jwt的值 同样需要client 和secret校验


//java 自带工具 生成jst非对称密钥：
//命令keytool -genkeypair -alias jwt -keyalg RSA -keysize 2048 -keystore D:/jwt/jwt.jks


//这是配置在nacos 的配置 命名为
//alibabaAuth-dev.yml
/**
 * server:
 *   port: 8900
 * spring:
 *   cloud:
 *     config:
 *     #本地配置优先(而且一定要配置在nacos 中，不要配置在app.yml或者boot.yml)   *重要
 *       override-none: true
 *     nacos:
 *       discovery:
 *         server-addr: 127.0.0.1:8848
 */

//如果使用认证服务器 具体流程：1,某一个登录客户端首先需要调用认证服务的四种模式的任意一个，一般自己的系统直接使用用户名密码 或者直接通过client和 secret 获取 token
//(如果以本项目作为认证中心，需要使用:http://localhost:8900/oauth/token?username=fox&password=123456&grant_type=password&client_id=client&client_secret=123123&scope=all)
//然后保存在redis对应的token，并返回给前台，前台每次请求带着对应的token
// 并发送到网关，网关通过filter 过滤器判断 当前的token是否有效 使用：localhost:8900/oauth/token_key 拿到公钥 : 然后根据发送给网关的token 判断这个token是否是合法的 同时还要判断这个token是不是 当前用户的 当然了 也可以简单些 直接拿着token 去调用 localhost:8900/oauth/check_token？token=发送的token 直接获取
/**
 * EG代码：
 *         String oriTokenKey = "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7bFKSPf8N2MH2ommLuZtwNYyB7DRWioKy+KYIniqGI1z0Syq00BAeLAugDirlh1jwqJvf8Md9v9OM/XfUnyokdCksQa2xYN3FsMJwRzr6zoseygdJVJd8bhb/i4r7wIwW47nkkewNzzjmZzPtUM5K+DaxNmR99y36R58ldqQZpComAgJWTCWLxuVT+D1y5+6UPFgLCoZczvSO+Sk6xH8z47v9i5X3G9tIjNw0FYQDLTWgnKO9QUWy1ShikMzhA597IM17X7VecBMTlIPxRQLeNsiDvADOVhoF9ek9b0Zch2X/SXD3zbROwcB0/Ji5DzuHHOZXekLWPIyNji2KUZjIQIDAQAB-----END PUBLIC KEY-----";
 *         //把获取的公钥开头和结尾替换掉
 *         String dealTokenKey =oriTokenKey.replaceAll("\\-*BEGIN PUBLIC KEY\\-*", "").replaceAll("\\-*END PUBLIC KEY\\-*", "").trim();
 *
 *         java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
 *
 *         X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(dealTokenKey));
 *
 *         KeyFactory keyFactory = KeyFactory.getInstance("RSA");
 *
 *         PublicKey publicKey = keyFactory.generatePublic(pubKeySpec);
 *
 *
 *         String jwtSecretRight = "HfkjksFKLJISJFKLFKWJFQFIQWIOFJQOFFQGGSDGFFJIQOEUFIEJFIOQWEFHFQOK5FKOIQWUFFEFE423FIQEOFJHUEWHFKASKDLQWJIFSJDJKFHJIJWO";
 *         byte[] utf8StrSec = jwtSecretRight.getBytes(StandardCharsets.UTF_8);
 *         String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MDEwNzY0NTQsInVzZXJfbmFtZSI6Inh5IiwianRpIjoiNzEyYThhYTktN2RlZi00N2M2LWEyNzctMDdjN2M0MTZhODI2IiwiY2xpZW50X2lkIjoiY2xpZW50Iiwic2NvcGUiOlsiYWxsIl19.PcKsGMmv2JBRZPAq-lExnlWihh_mcEGW-6OLSUYN6do";
 *         io.jsonwebtoken.Jwt<JwsHeader, Claims> parseClaimsJwt = Jwts.parser().setSigningKey(utf8StrSec).parseClaimsJws(token);
 *         Claims claims = parseClaimsJwt.getBody(); //有异常 token校验失败，没有异常 token校验成功
 */


// 当然简便方法 还有一个特别好用的接口，直接获取token 对应的信息，并能判断出是不是有效的 （但是不安全）：localhost:8900/oauth/check_token?token=上一步的token
// 如果有效放行到具体的服务，无效返回错误信息。


public class AuthApplication {
    public static void main(String[] args) {
        SpringApplication.run(AuthApplication.class, args);
    }
}
